package com.kyivmohyla.kma2.client.presenter.operator;

import com.google.gwt.event.dom.client.*;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.media.client.Audio;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.user.datepicker.client.DateBox;
import com.google.gwt.view.client.ListDataProvider;
import com.kyivmohyla.kma2.client.LoginService;
import com.kyivmohyla.kma2.client.UserService;
import com.kyivmohyla.kma2.client.events.operator.OperatorCloseOrderEvent;
import com.kyivmohyla.kma2.client.gin.Injector;
import com.kyivmohyla.kma2.client.presenter.Presenter;
import com.kyivmohyla.kma2.client.presenter.refbook.ServiceReferenceBookPresenter;
import com.kyivmohyla.kma2.client.utils.Dialog;
import com.kyivmohyla.kma2.client.view.common.OrderHistoryWidget;
import com.kyivmohyla.kma2.client.view.common.ServiceCellTableWidget;
import com.kyivmohyla.kma2.shared.model.*;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class OperatorEditOrderPresenter implements Presenter {

    private final static String timeFormatString = "HH:mm";
    private final static String dateFormatString = "dd.MM.yyyy";
    private final static DateTimeFormat timeFormat = DateTimeFormat.getFormat(timeFormatString);
    private final static DateTimeFormat dateFormat = DateTimeFormat.getFormat(dateFormatString);
    private final Display display;
    private final Injector injector = Injector.INSTANCE;
    private boolean changesWereMade;
    private int customerIdOnOrder;
    private UIOrder existingOrder;
    private List<UIService> servicesOnOrder;
    private List<UIService> servicesOnOrderToShow;
    private List<UIService> servicesOnOrderToSave;
    private List<UIService> servicesOnOrderToDelete;

    public OperatorEditOrderPresenter() {
        this.display = injector.getOperatorEditOrderWindowView();
        this.display.getState().setText("New");
        this.display.getDesirableDate().setFireNullValues(true);
        this.customerIdOnOrder = -1;
        fillTimeListBoxes();
        bind();
        ListDataProvider<UIHistory> historyListDataProvider = new ListDataProvider<UIHistory>();
        ListDataProvider<UIService> serviceListDataProvider = new ListDataProvider<UIService>();
        serviceListDataProvider.addDataDisplay(display.getServiceCellTable().getServiceCellTable());
        historyListDataProvider.addDataDisplay(display.getOrderHistoryCellTable().getOrderHistoryCellTable());
        changesWereMade = false;
    }

    public OperatorEditOrderPresenter(UIImportOrder importOrder) {
        this.display = injector.getOperatorEditOrderWindowView();
        this.display.getState().setText("New");
        this.display.getDesirableDate().setFireNullValues(true);
        this.customerIdOnOrder = -1;
        fillTimeListBoxes();
        bind();
        ListDataProvider<UIHistory> historyListDataProvider = new ListDataProvider<UIHistory>();
        ListDataProvider<UIService> serviceListDataProvider = new ListDataProvider<UIService>();
        serviceListDataProvider.addDataDisplay(display.getServiceCellTable().getServiceCellTable());
        historyListDataProvider.addDataDisplay(display.getOrderHistoryCellTable().getOrderHistoryCellTable());

        changesWereMade = true;
        this.display.getCustomerName().setText(importOrder.getCustomerName());
        this.display.getCustomerAddress().setText(importOrder.getCustomerAddress());
        this.display.getCustomerPhone().setText(importOrder.getCustomerPhone());
        this.display.getCustomerEmail().setText(importOrder.getCustomerEmail());
        this.display.getCommentary().setText(importOrder.getCommentary());

        this.display.getDesirableDate().setFormat(new DateBox.DefaultFormat(dateFormat));
        this.display.getDesirableDate().getTextBox().setText(dateFormat.format(importOrder.getDesirableStart()));

        selectTimeInListBox(importOrder.getDesirableStart(), display.getDesirableStartTime());
        selectTimeInListBox(importOrder.getDesirableEnd(), display.getDesirableEndTime());


        customerPhoneIsValid();
        customerEmailIsValid();

        doValidateStuff();
        validateFields();
    }

    public OperatorEditOrderPresenter(UIOrder order) {
        this.display = injector.getOperatorEditOrderWindowView();
        bind();
        fillTimeListBoxes();
        this.customerIdOnOrder = order.getCustomerId();
        this.existingOrder = order;
        this.display.getDesirableDate().setFireNullValues(true);
        this.display.getState().setText(order.getStateName());
        this.display.getCustomerName().setText(order.getCustomerName());
        this.display.getCustomerAddress().setText(order.getCustomerAddress());
        this.display.getCommentary().setText(order.getCommentary());

        this.display.getDesirableDate().setFormat(new DateBox.DefaultFormat(dateFormat));
        this.display.getDesirableDate().getTextBox().setText(dateFormat.format(order.getDesStartDate()));

        selectTimeInListBox(order.getDesStartDate(), display.getDesirableStartTime());
        selectTimeInListBox(order.getDesEndDate(), display.getDesirableEndTime());

        UserService.App.getInstance().getCustomerById(order.getCustomerId(), new AsyncCallback<UICustomer>() {
            @Override
            public void onFailure(Throwable caught) {
                Dialog.getInstance().createDialogBoxWithMessage("Error", caught.getMessage());
            }

            @Override
            public void onSuccess(UICustomer result) {
                display.getCustomerPhone().setText(result.getPhone());
                display.getCustomerEmail().setText(result.getEmail());
                doValidateCustomerPhone();
                if (customerPhoneIsValid())
                    changesWereMade = false;
                doValidateCustomerEmail();
                if (customerEmailIsValid())
                    changesWereMade = false;
            }
        });
        UserService.App.getInstance().getHistoryByOrderId(order.getOrderId(), new AsyncCallback<List<UIHistory>>() {
            @Override
            public void onFailure(Throwable throwable) {
                Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
            }

            @Override
            public void onSuccess(List<UIHistory> uiHistories) {
                ListDataProvider<UIHistory> dataProvider = new ListDataProvider<UIHistory>(uiHistories);
                dataProvider.addDataDisplay(display.getOrderHistoryCellTable().getOrderHistoryCellTable());
            }
        });
        UserService.App.getInstance().getServiceByOrderId(existingOrder.getOrderId(), new AsyncCallback<List<UIService>>() {
            @Override
            public void onFailure(Throwable caught) {
                Dialog.getInstance().createDialogBoxWithMessage("Error", caught.getMessage());
            }

            @Override
            public void onSuccess(List<UIService> result) {
                servicesOnOrder = new ArrayList<UIService>(result);
                servicesOnOrderToShow = new ArrayList<UIService>(result);
                ListDataProvider<UIService> dataProvider = new ListDataProvider<UIService>(servicesOnOrderToShow);
                dataProvider.addDataDisplay(display.getServiceCellTable().getServiceCellTable());
            }
        });
        changesWereMade = false;
        doValidateStuff();
        if (validateFields()) {
            changesWereMade = false;
        }
    }

    private void fillTimeListBoxes() {
        boolean thirtyIsPut = false;
        for (int i = 8; i < 21; ) {
            display.getDesirableStartTime().addItem(((i < 10) ? "0" + i : i) + ":" + (thirtyIsPut ? "30" : "00"));
            display.getDesirableEndTime().addItem(((i < 10) ? "0" + i : i) + ":" + (thirtyIsPut ? "30" : "00"));
            if (thirtyIsPut) i++;
            thirtyIsPut = !thirtyIsPut;
        }
        display.getDesirableEndTime().removeItem(0);
        display.getDesirableEndTime().addItem("21:00");
    }

    private void selectTimeInListBox(Date time, ListBox listBox) {
        //todo maybe change those deprecated methods
        int hours = time.getHours();
        int minutes = time.getMinutes();
        String parsedTime = "" + (hours < 10 ? "0" + hours : hours) + ":" + (minutes < 10 ? "0" + minutes : minutes);
        for (int i = 0; i < listBox.getItemCount(); i++)
            if (listBox.getValue(i).equals(parsedTime)) {
                listBox.setItemSelected(i, true);
                break;
            }
    }

    private String getSelectedValue(ListBox listBox) {
        return listBox.getValue(listBox.getSelectedIndex());
    }

    private Date createDateFromString(String date, String time) {
        String[] dateArray = date.split("\\.");
        String[] timeArray = time.split(":");
        return new Date(Integer.parseInt(dateArray[2]) - 1900,
                Integer.parseInt(dateArray[1]) - 1,
                Integer.parseInt(dateArray[0]),
                Integer.parseInt(timeArray[0]),
                Integer.parseInt(timeArray[1]), 0);
    }

    private boolean isToday(Date date) {
        Date rightNow = new Date();
        return date != null && rightNow.getYear() == date.getYear() && rightNow.getMonth() == date.getMonth() && rightNow.getDate() == date.getDate();
    }

    private boolean customerNameIsValid() {
        //todo rewrite this stupid code with one fancy regular expression, because I can not
        return this.display.getCustomerName().getText().matches("[a-zA-Z'-/D ]+") &&
                this.display.getCustomerName().getText().split(" ").length < 4 &&
                this.display.getCustomerName().getText().split(" ").length > 1 &&
                !this.display.getCustomerName().getText().equals("");
    }

    private boolean customerAddressIsValid() {
        return !this.display.getCustomerAddress().getText().isEmpty();
    }

    private boolean customerEmailIsValid() {
        return this.display.getCustomerEmail().getText().matches("^[-\\w.]+@([A-z0-9][-A-z0-9]+\\.)+[A-z]{2,4}$");
    }

    private boolean customerPhoneIsValid() {
        return !this.display.getCustomerPhone().getText().isEmpty();
    }

    private boolean commentaryIsValid() {
        return !this.display.getCommentary().getText().isEmpty();
    }

    private boolean validateFields() {
        return (commentaryIsValid() &&
                customerAddressIsValid() && customerNameIsValid() &&
                (dateValidation() == 0) && (timeValidation() == 0));
    }

    // returns 0  if ok,
    // returns 1  if format error,
    // returns -1 if scheduling for past date.
    // returns 2  if date is ok, but time is already past
    private int dateValidation() {
        try {
            //checking if wrong format
            dateFormat.parse(this.display.getDesirableDate().getTextBox().getText());
        } catch (IllegalArgumentException e) {
            return 1;
        }
        //if today, we have to check time
        if (isToday(display.getDesirableDate().getValue())) {
            if (timeValidation() == -1) {
                return 2;
            }
        }
        return (display.getDesirableDate().getValue().getTime() >= dateFormat.parse(dateFormat.format(new Date())).getTime()) ? 0 : -1;
    }

    // returns 0  if ok
    // returns 1  if endTime is earlier than startTime
    // returns -1 if scheduling for past time
    // returns 2 if endTime is earlier than startTime and scheduling for past time
    private int timeValidation() {
        if (isToday(display.getDesirableDate().getValue())) {
            if (!timeFormat.parse(display.getDesirableStartTime().getValue(display.getDesirableStartTime().getSelectedIndex()))
                    .before(timeFormat.parse(display.getDesirableEndTime().getValue(display.getDesirableEndTime().getSelectedIndex())))) {
                if (timeFormat.parse(display.getDesirableStartTime().getValue(display.getDesirableStartTime().getSelectedIndex())).getTime() > System.currentTimeMillis()) {
                    return 1;
                } else {
                    return 2;
                }
            } else {
                if (timeFormat.parse(display.getDesirableStartTime().getValue(display.getDesirableStartTime().getSelectedIndex())).getTime() > System.currentTimeMillis()) {
                    return 0;
                } else {
                    return -1;
                }
            }
        } else {
            if (dateValidation() == -1) {
                if (!timeFormat.parse(display.getDesirableStartTime().getValue(display.getDesirableStartTime().getSelectedIndex()))
                        .before(timeFormat.parse(display.getDesirableEndTime().getValue(display.getDesirableEndTime().getSelectedIndex())))) {
                    return 2;
                } else {
                    return -1;
                }
            } else {
                if (!timeFormat.parse(display.getDesirableStartTime().getValue(display.getDesirableStartTime().getSelectedIndex()))
                        .before(timeFormat.parse(display.getDesirableEndTime().getValue(display.getDesirableEndTime().getSelectedIndex())))) {
                    return 1;
                } else {
                    return 0;
                }
            }
        }
    }

    private void doValidateDate() {
        changesWereMade = true;
        if (dateValidation() == 2) {
            display.getDesirableDateInfoLabel().setText(" Date is correct. Check Time");
            ((Label) display.getDesirableDateInfoLabel()).setStyleName("kma-InputWarning");
            display.getDesirableStartTimeInfoLabel().setText(" Provide future Time");
            ((Label) display.getDesirableStartTimeInfoLabel()).setStyleName("kma-InputIsInvalid");
        } else if (dateValidation() == 0) {
            display.getDesirableDateInfoLabel().setText(" Date is correct");
            ((Label) display.getDesirableDateInfoLabel()).setStyleName("kma-InputIsValid");
            if (timeValidation() == 0) {
                display.getDesirableStartTimeInfoLabel().setText(" OK");
                ((Label) display.getDesirableStartTimeInfoLabel()).setStyleName("kma-InputIsValid");
            }
        } else if (dateValidation() == 1) {
            display.getDesirableDateInfoLabel().setText("Please provide date in \'" + dateFormatString.toLowerCase() + "\' format");
            ((Label) display.getDesirableDateInfoLabel()).setStyleName("kma-InputIsInvalid");
            display.getDesirableStartTimeInfoLabel().setText("");
        } else if (dateValidation() == -1) {
            display.getDesirableDateInfoLabel().setText("You can not schedule for past date");
            ((Label) display.getDesirableDateInfoLabel()).setStyleName("kma-InputIsInvalid");
            display.getDesirableStartTimeInfoLabel().setText("You can not schedule for past time");
            ((Label) display.getDesirableStartTimeInfoLabel()).setStyleName("kma-InputIsInvalid");
        }
    }

    private void doValidateTime(ListBox changedList, ListBox dependentList) {
        changesWereMade = true;
        display.getDesirableStartTimeInfoLabel().setText("");
        switch (timeValidation()) {
            case 0:
                display.getDesirableStartTimeInfoLabel().setText(" OK");
                ((Label) display.getDesirableStartTimeInfoLabel()).setStyleName("kma-InputIsValid");
                break;
            case 1:
                dependentList.setSelectedIndex(changedList.getSelectedIndex());
                display.getDesirableStartTimeInfoLabel().setText(" OK");
                ((Label) display.getDesirableStartTimeInfoLabel()).setStyleName("kma-InputIsValid");
                break;
            case 2:
                dependentList.setSelectedIndex(changedList.getSelectedIndex());
                display.getDesirableStartTimeInfoLabel().setText("You can not schedule for past time");
                ((Label) display.getDesirableStartTimeInfoLabel()).setStyleName("kma-InputIsInvalid");
                break;
            case -1:
                display.getDesirableStartTimeInfoLabel().setText("You can not schedule for past time");
                ((Label) display.getDesirableStartTimeInfoLabel()).setStyleName("kma-InputIsInvalid");
                break;
        }
    }

    private void doValidateCustomerName() {
        changesWereMade = true;
        if (!customerNameIsValid()) {
            display.getCustomerNameInfoLabel().setText("Please provide name in 'First [Middle] Last' format");
            ((Label) display.getCustomerNameInfoLabel()).setStyleName("kma-InputIsInvalid");
            ((TextBox) display.getCustomerName()).setStyleName("kma-textBoxDataIsInvalid");
        } else {
            display.getCustomerNameInfoLabel().setText("OK");
            ((Label) display.getCustomerNameInfoLabel()).setStyleName("kma-InputIsValid");
            ((TextBox) display.getCustomerName()).setStyleName("kma-textBoxDataIsValid");
        }
    }

    private void doValidateCustomerAddress() {
        changesWereMade = true;
        if (!customerAddressIsValid()) {
            display.getCustomerAddressInfoLabel().setText("Please provide address");
            ((Label) display.getCustomerAddressInfoLabel()).setStyleName("kma-InputIsInvalid");
            ((TextArea) display.getCustomerAddress()).setStyleName("kma-textBoxDataIsInvalid");
        } else {
            display.getCustomerAddressInfoLabel().setText("OK");
            ((Label) display.getCustomerAddressInfoLabel()).setStyleName("kma-InputIsValid");
            ((TextArea) display.getCustomerAddress()).setStyleName("kma-textBoxDataIsValid");
        }
    }

    private void doValidateCustomerEmail() {
        changesWereMade = true;
        if (!customerEmailIsValid()) {
            display.getCustomerEmailInfoLabel().setText("Please provide correct email address");
            ((Label) display.getCustomerEmailInfoLabel()).setStyleName("kma-InputIsInvalid");
            ((TextBox) display.getCustomerEmail()).setStyleName("kma-textBoxDataIsInvalid");
        } else {
            display.getCustomerEmailInfoLabel().setText("OK");
            ((Label) display.getCustomerEmailInfoLabel()).setStyleName("kma-InputIsValid");
            ((TextBox) display.getCustomerEmail()).setStyleName("kma-textBoxDataIsValid");
        }
    }

    private void doValidateCustomerPhone() {
        changesWereMade = true;
        if (!customerPhoneIsValid()) {
            display.getCustomerPhoneInfoLabel().setText("Please provide phone number");
            ((Label) display.getCustomerPhoneInfoLabel()).setStyleName("kma-InputIsInvalid");
            ((TextBox) display.getCustomerPhone()).setStyleName("kma-textBoxDataIsInvalid");
        } else {
            display.getCustomerPhoneInfoLabel().setText("OK");
            ((Label) display.getCustomerPhoneInfoLabel()).setStyleName("kma-InputIsValid");
            ((TextBox) display.getCustomerPhone()).setStyleName("kma-textBoxDataIsValid");
        }
    }

    private void doValidateCommentary() {
        changesWereMade = true;
        if (!commentaryIsValid()) {
            display.getCommentaryInfoLabel().setText("Please provide some customer commentary");
            ((Label) display.getCommentaryInfoLabel()).setStyleName("kma-InputIsInvalid");
            ((TextArea) display.getCommentary()).setStyleName("kma-textBoxDataIsInvalid");
        } else {
            display.getCommentaryInfoLabel().setText("OK");
            ((Label) display.getCommentaryInfoLabel()).setStyleName("kma-InputIsValid");
            ((TextArea) display.getCommentary()).setStyleName("kma-textBoxDataIsValid");
        }
    }

    private void doValidateStuff() {
        doValidateDate();
        doValidateTime(display.getDesirableStartTime(), display.getDesirableEndTime());
        doValidateCommentary();
        doValidateCustomerName();
        doValidateCustomerAddress();
    }

    private void bindFieldValidationHandlers() {

        this.display.getDesirableDate().addValueChangeHandler(new ValueChangeHandler<Date>() {
            @Override
            public void onValueChange(ValueChangeEvent<Date> event) {
                doValidateDate();
            }
        });
        this.display.getDesirableStartTime().addChangeHandler(new ChangeHandler() {
            @Override
            public void onChange(ChangeEvent event) {
                doValidateTime(display.getDesirableStartTime(), display.getDesirableEndTime());
            }
        });
        this.display.getDesirableEndTime().addChangeHandler(new ChangeHandler() {
            @Override
            public void onChange(ChangeEvent event) {
                doValidateTime(display.getDesirableEndTime(), display.getDesirableStartTime());
            }
        });

        ((TextBox) this.display.getCustomerName()).addValueChangeHandler(new ValueChangeHandler<String>() {
            @Override
            public void onValueChange(ValueChangeEvent<String> event) {
                doValidateCustomerName();
            }
        });
        ((TextArea) this.display.getCustomerAddress()).addValueChangeHandler(new ValueChangeHandler<String>() {
            @Override
            public void onValueChange(ValueChangeEvent<String> event) {
                doValidateCustomerAddress();
            }
        });
        ((TextBox) this.display.getCustomerEmail()).addValueChangeHandler(new ValueChangeHandler<String>() {
            @Override
            public void onValueChange(ValueChangeEvent<String> event) {
                doValidateCustomerEmail();
            }
        });
        ((TextBox) this.display.getCustomerPhone()).addValueChangeHandler(new ValueChangeHandler<String>() {
            @Override
            public void onValueChange(ValueChangeEvent<String> event) {
                doValidateCustomerPhone();
            }
        });
        ((TextArea) this.display.getCommentary()).addValueChangeHandler(new ValueChangeHandler<String>() {
            @Override
            public void onValueChange(ValueChangeEvent<String> event) {
                doValidateCommentary();
            }
        });

    }

    private void bind() {
        bindFieldValidationHandlers();
        this.display.getDeleteOrderButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent clickEvent) {
                doDeleteOrder();
            }
        });
        this.display.getSaveOrderButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                doSaveOrder(false);
            }
        });
//        this.display.getSaveAndCloseButton().addClickHandler(new ClickHandler() {
//            @Override
//            public void onClick(ClickEvent clickEvent) {
//                doSaveOrder(true);
//            }
//        });
//        this.display.getCancelButton().addClickHandler(new ClickHandler() {
//            @Override
//            public void onClick(ClickEvent clickEvent) {
//                if (!changesWereMade) {
//                    injector.getEventBus().fireEvent(new OperatorCloseOrderEvent());
//                } else {
//                    DiscardChangesDialogBox.getInstance().createDialogBox(injector, new OperatorCloseOrderEvent());
//                }
//            }
//        });
        this.display.getCancelButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent clickEvent) {
                if (!changesWereMade) {
                    injector.getEventBus().fireEvent(new OperatorCloseOrderEvent());
                } else {
                    Audio openSound = Audio.createIfSupported();
                    final DialogBox dialogBox = new DialogBox();
                    dialogBox.addStyleName("gwt-DialogBox");
                    dialogBox.setText("Confirmation");
                    HTML message = new HTML("<center>Save changes</center>");
                    VerticalPanel dialogContents = new VerticalPanel();
                    dialogContents.addStyleName("dialogContents");
                    dialogContents.setSpacing(4);
                    dialogBox.setWidget(dialogContents);
                    Button yes = new Button("Yes", new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                            dialogBox.hide();
                            doSaveOrder(true);
                        }
                    });
                    Button no = new Button("No", new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                            dialogBox.hide();
                            injector.getEventBus().fireEvent(new OperatorCloseOrderEvent());
                        }
                    });
                    Button cancel = new Button("Cancel", new ClickHandler() {
                        @Override
                        public void onClick(ClickEvent event) {
                            dialogBox.hide();
                        }
                    });
                    HorizontalPanel buttons = new HorizontalPanel();
                    buttons.add(yes);
                    buttons.add(no);
                    buttons.add(cancel);
                    dialogContents.add(message);
                    dialogContents.add(buttons);
                    dialogContents.setStyleName("dialogContents");
                    dialogContents.setCellHorizontalAlignment(message, HasHorizontalAlignment.ALIGN_CENTER);
                    dialogContents.setCellVerticalAlignment(message, HasVerticalAlignment.ALIGN_MIDDLE);
                    dialogContents.setCellHorizontalAlignment(buttons, HasHorizontalAlignment.ALIGN_CENTER);
                    dialogContents.setCellVerticalAlignment(buttons, HasVerticalAlignment.ALIGN_BOTTOM);
                    dialogBox.setWidget(dialogContents);
                    dialogBox.setAnimationEnabled(true);
                    dialogBox.center();
                    openSound.setSrc("sounds/Windows Notify System Generic.wav");
                    openSound.play();
                    dialogBox.show();
                }
            }
        });
        this.display.getAccessButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent clickEvent) {
                doChangeState(2);
            }
        });
        this.display.getCloseButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent clickEvent) {
                doChangeState(6);
            }
        });
        this.display.getManageServicesButton().addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                changesWereMade = true;
                final DialogBox dialogBox = new DialogBox();
                dialogBox.addStyleName("gwt-DialogBox");
                dialogBox.setText("Service Reference Book");
                VerticalPanel dialogContents = new VerticalPanel();
                dialogContents.addStyleName("dialogContents");
                dialogContents.setSpacing(4);
                dialogBox.setWidget(dialogContents);
                final ServiceReferenceBookPresenter serviceReferenceBookPresenter;
                if (servicesOnOrderToShow == null) {
                    serviceReferenceBookPresenter = new ServiceReferenceBookPresenter();
                } else {
                    serviceReferenceBookPresenter = new ServiceReferenceBookPresenter(servicesOnOrderToShow);
                }
                dialogContents.add(serviceReferenceBookPresenter.getDisplay().asWidget());
                serviceReferenceBookPresenter.getDisplay().getAddButton().addClickHandler(new ClickHandler() {
                    @Override
                    public void onClick(ClickEvent clickEvent) {
                        dialogBox.hide();
                        if (servicesOnOrder != null) {
                            servicesOnOrderToDelete = new ArrayList<UIService>(servicesOnOrder);
                            servicesOnOrderToDelete.removeAll(serviceReferenceBookPresenter.getServicesOnOrder());
                            servicesOnOrderToSave = new ArrayList<UIService>(serviceReferenceBookPresenter.getServicesOnOrder());
                            servicesOnOrderToSave.removeAll(servicesOnOrder);
                        } else {
                            servicesOnOrderToSave = new ArrayList<UIService>(serviceReferenceBookPresenter.getServicesOnOrder());
                        }
//                        System.out.println(servicesOnOrderToSave);
//                        System.out.println(servicesOnOrderToDelete);
                        servicesOnOrderToShow = new ArrayList<UIService>(serviceReferenceBookPresenter.getServicesOnOrder());
                        ListDataProvider<UIService> dataProvider = new ListDataProvider<UIService>(servicesOnOrderToShow);
                        dataProvider.addDataDisplay(display.getServiceCellTable().getServiceCellTable());
                    }
                });
                serviceReferenceBookPresenter.getDisplay().getCancelButton().addClickHandler(new ClickHandler() {
                    @Override
                    public void onClick(ClickEvent clickEvent) {
                        dialogBox.hide();
                    }
                });
                dialogBox.setGlassEnabled(true);
                dialogBox.setAnimationEnabled(true);
                dialogBox.center();
                dialogBox.show();
            }
        });
    }

    private void doChangeState(int state) {
        if (this.existingOrder != null && !changesWereMade && validateFields()) {
            this.existingOrder.setStateId(state);
            this.existingOrder.setCommentary(this.display.getCommentary().getText());
            UserService.App.getInstance().updateOrder(this.existingOrder, new AsyncCallback<Void>() {
                @Override
                public void onFailure(Throwable throwable) {
                    Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                }

                @Override
                public void onSuccess(Void aVoid) {
                    Dialog.getInstance().createDialogBoxWithMessage("Success", "Order's state was changed.");
                    injector.getEventBus().fireEvent(new OperatorCloseOrderEvent());
                }
            });
            final UIHistory history = new UIHistory();
            history.setChangeDate(new Date());
            history.setNewState(state);
            history.setOrderId(this.existingOrder.getOrderId());

            history.setCommentary(this.display.getMyCommentary().getText());
            LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                @Override
                public void onFailure(Throwable throwable) {
                    Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                }

                @Override
                public void onSuccess(UIStaff staff) {
                    history.setStaffId(staff.getStaffId());
                    UserService.App.getInstance().addHistory(history, new AsyncCallback<Void>() {
                        @Override
                        public void onFailure(Throwable throwable) {
                            Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                        }

                        @Override
                        public void onSuccess(Void aVoid) {
                        }
                    });
                }
            });
        } else {
            String message = "Order is not created yet.<br>In order to do this, provide necessary fields, and hit \"Save\" button.";
            if (changesWereMade)
                message = "You've probably made some changes or some fields are not correct. Please hit \"Save\" button, just to be sure.";
            if (!validateFields())
                message = "There are some fields, that are highlighted in red or have invalid data.<br>Please provide correct information to them.";
            Dialog.getInstance().createDialogBoxWithMessage("Important", message);
        }
    }

    private void doDeleteOrder() {
        if (this.existingOrder != null && this.existingOrder.getStateId() == 1) {
//        if (this.existingOrder != null && this.existingOrder.getStateId() == 1 && !changesWereMade) {
            UserService.App.getInstance().deleteOrderServEquipByOrderId(this.existingOrder.getOrderId(), new AsyncCallback<Void>() {
                @Override
                public void onFailure(Throwable caught) {
                    Dialog.getInstance().createDialogBoxWithMessage("Error", "Can not delete order");
                }

                @Override
                public void onSuccess(Void result) {
                    UserService.App.getInstance().deleteOrder(existingOrder, new AsyncCallback<Void>() {
                        @Override
                        public void onFailure(Throwable throwable) {
                            Dialog.getInstance().createDialogBoxWithMessage("Error", "Can not delete order");
                        }

                        @Override
                        public void onSuccess(Void aVoid) {
                            injector.getEventBus().fireEvent(new OperatorCloseOrderEvent());
                        }
                    });
                }
            });
        } else {
            String message = "You can not delete rejected order";
            if (this.existingOrder == null) {
                message = "Order was not created yet";
            }
            Dialog.getInstance().createDialogBoxWithMessage("Important", message);
        }
    }

    private void doSaveOrder(final boolean userWantsToCloseWindow) {
        ((Button) display.getSaveOrderButton()).setEnabled(false);
//        ((Button) display.getSaveAndCloseButton()).setEnabled(false);
        if (validateFields() && servicesOnOrderToShow != null && !servicesOnOrderToShow.isEmpty() && customerPhoneIsValid() && customerEmailIsValid()) {
            final UICustomer customer = new UICustomer();
            customer.setEmail(this.display.getCustomerEmail().getText());
            customer.setPhone(this.display.getCustomerPhone().getText());
            customer.setAddress(this.display.getCustomerAddress().getText());
            //todo rewrite this stupid section
            String[] customerName = this.display.getCustomerName().getText().split(" ");
            if (customerName.length == 2) {
                customer.setFirstName(customerName[0]);
                customer.setLastName(customerName[1]);
            } else if (customerName.length == 3) {
                customer.setFirstName(customerName[0] + " " + customerName[1]);
                customer.setLastName(customerName[2]);
            }
            //todo end of stupid section
            final UIOrder uiOrder = new UIOrder();
            uiOrder.setStateId(1);
            if (this.existingOrder == null)
                uiOrder.setCreateDate(new Timestamp(new Date().getTime()));
            else
                uiOrder.setCreateDate(this.existingOrder.getCreateDate());
            uiOrder.setDesStartDate(createDateFromString(display.getDesirableDate().getTextBox().getText(), getSelectedValue(display.getDesirableStartTime())));
            uiOrder.setDesEndDate(createDateFromString(display.getDesirableDate().getTextBox().getText(), getSelectedValue(display.getDesirableEndTime())));

            uiOrder.setCommentary(this.display.getCommentary().getText());
            uiOrder.setEngineerId(0);
            if (this.customerIdOnOrder == -1) {
                UserService.App.getInstance().addCustomer(customer, new AsyncCallback<Void>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(Void aVoid) {
                        UserService.App.getInstance().getCustomerWithMaxId(new AsyncCallback<UICustomer>() {
                            @Override
                            public void onFailure(Throwable throwable) {
                                Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                            }

                            @Override
                            public void onSuccess(UICustomer uiCustomer) {
                                customerIdOnOrder = uiCustomer.getCustomerId();
                                uiOrder.setCustomerId(uiCustomer.getCustomerId());
                                UserService.App.getInstance().addOrder(uiOrder, new AsyncCallback<Void>() {
                                    @Override
                                    public void onFailure(Throwable throwable) {
                                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                                    }

                                    @Override
                                    public void onSuccess(Void result) {
                                        UserService.App.getInstance().getOrderWithMaxId(new AsyncCallback<UIOrder>() {
                                            @Override
                                            public void onFailure(Throwable throwable) {
                                                Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                                            }

                                            @Override
                                            public void onSuccess(UIOrder uiOrder) {
                                                existingOrder = uiOrder;
                                                final List<UIOrderServEquip> orderServEquipsToSave = new ArrayList<UIOrderServEquip>();
                                                final List<UIOrderServEquip> orderServEquipsToDelete = new ArrayList<UIOrderServEquip>();
                                                if (servicesOnOrderToSave != null) {
                                                    for (UIService service : servicesOnOrderToSave) {
                                                        orderServEquipsToSave.add(new UIOrderServEquip(existingOrder.getOrderId(), service.getServiceId()));
                                                    }
                                                    servicesOnOrderToSave.clear();
                                                }
                                                if (servicesOnOrderToDelete != null) {
                                                    for (UIService service : servicesOnOrderToDelete) {
                                                        orderServEquipsToDelete.add(new UIOrderServEquip(existingOrder.getOrderId(), service.getServiceId()));
                                                    }
                                                    servicesOnOrderToDelete.clear();
                                                }
                                                UserService.App.getInstance().deleteOrderServEquipList(orderServEquipsToDelete, new AsyncCallback<Void>() {
                                                    @Override
                                                    public void onFailure(Throwable throwable) {
                                                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                                                    }

                                                    @Override
                                                    public void onSuccess(Void aVoid) {
                                                        UserService.App.getInstance().addOrderServEquipList(orderServEquipsToSave, new AsyncCallback<Void>() {
                                                            @Override
                                                            public void onFailure(Throwable throwable) {
                                                                Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                                                            }

                                                            @Override
                                                            public void onSuccess(Void aVoid) {
                                                                servicesOnOrder = new ArrayList<UIService>(servicesOnOrderToShow);
                                                                Dialog.getInstance().createDialogBoxWithMessage("Success", "Customer and Order were created.");
                                                                ((Button) display.getSaveOrderButton()).setEnabled(true);
//                                                                ((Button) display.getSaveAndCloseButton()).setEnabled(true);
                                                                if (userWantsToCloseWindow) {
                                                                    injector.getEventBus().fireEvent(new OperatorCloseOrderEvent());
                                                                }
                                                            }
                                                        });
                                                    }
                                                });
                                            }
                                        });
                                    }
                                });
                            }
                        });
                    }
                });
            } else {
                customer.setCustomerId(this.customerIdOnOrder);
                UserService.App.getInstance().updateCustomer(customer, new AsyncCallback<Void>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(Void aVoid) {
                        uiOrder.setCustomerId(customerIdOnOrder);
                        uiOrder.setOrderId(existingOrder.getOrderId());
                        uiOrder.setEngineerId(existingOrder.getEngineerId());
                        UserService.App.getInstance().updateOrder(uiOrder, new AsyncCallback<Void>() {
                            @Override
                            public void onFailure(Throwable throwable) {
                                Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                            }

                            @Override
                            public void onSuccess(Void result) {
                                existingOrder = uiOrder;
                                final List<UIOrderServEquip> orderServEquipsToSave = new ArrayList<UIOrderServEquip>();
                                final List<UIOrderServEquip> orderServEquipsToDelete = new ArrayList<UIOrderServEquip>();
                                if (servicesOnOrderToSave != null) {
                                    for (UIService service : servicesOnOrderToSave) {
                                        orderServEquipsToSave.add(new UIOrderServEquip(existingOrder.getOrderId(), service.getServiceId()));
                                    }
                                    servicesOnOrderToSave.clear();
                                }
                                if (servicesOnOrderToDelete != null) {
                                    for (UIService service : servicesOnOrderToDelete) {
                                        orderServEquipsToDelete.add(new UIOrderServEquip(existingOrder.getOrderId(), service.getServiceId()));
                                    }
                                    servicesOnOrderToDelete.clear();
                                }
                                UserService.App.getInstance().deleteOrderServEquipList(orderServEquipsToDelete, new AsyncCallback<Void>() {
                                    @Override
                                    public void onFailure(Throwable throwable) {
                                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                                    }

                                    @Override
                                    public void onSuccess(Void aVoid) {
                                        UserService.App.getInstance().addOrderServEquipList(orderServEquipsToSave, new AsyncCallback<Void>() {
                                            @Override
                                            public void onFailure(Throwable throwable) {
                                                Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                                            }

                                            @Override
                                            public void onSuccess(Void aVoid) {
                                                servicesOnOrder = new ArrayList<UIService>(servicesOnOrderToShow);
                                                Dialog.getInstance().createDialogBoxWithMessage("Success", "Customer and Order were updated.");
                                                ((Button) display.getSaveOrderButton()).setEnabled(true);
//                                                ((Button) display.getSaveAndCloseButton()).setEnabled(true);
                                                if (userWantsToCloseWindow) {
                                                    injector.getEventBus().fireEvent(new OperatorCloseOrderEvent());
                                                }
                                            }
                                        });
                                    }
                                });
                            }
                        });
                    }
                });
            }
            changesWereMade = false;
        } else {
            String message = "There are some fields, that are highlighted in red or have invalid data.<br>Please provide correct information to them.";
            if (servicesOnOrderToShow == null || servicesOnOrderToShow.isEmpty()) {
                message = "You have to add some Service using \"Manage Services\" button";
            }
            Dialog.getInstance().createDialogBoxWithMessage("Important", message);
            ((Button) display.getSaveOrderButton()).setEnabled(true);
//            ((Button) display.getSaveAndCloseButton()).setEnabled(true);
        }
    }

    @Override
    public void go(HasWidgets container) {
        container.clear();
        container.add(display.asWidget());
    }

    public interface Display {
        HasText getCustomerNameInfoLabel();

        HasText getCustomerAddressInfoLabel();

        HasText getCustomerEmailInfoLabel();

        HasText getCustomerPhoneInfoLabel();

        HasText getDesirableDateInfoLabel();

        HasText getCommentaryInfoLabel();

        HasText getState();

        HasText getCustomerName();

        HasText getCustomerPhone();

        HasText getCustomerAddress();

        HasText getCustomerEmail();

        DateBox getDesirableDate();

        ListBox getDesirableStartTime();

        ListBox getDesirableEndTime();

        HasText getMyCommentary();

        HasText getCommentary();

        HasClickHandlers getManageServicesButton();

        HasClickHandlers getDeleteOrderButton();

        HasClickHandlers getSaveOrderButton();

//        HasClickHandlers getSaveAndCloseButton();

        HasClickHandlers getCancelButton();

        HasClickHandlers getAccessButton();

        HasClickHandlers getCloseButton();

        OrderHistoryWidget getOrderHistoryCellTable();

        ServiceCellTableWidget getServiceCellTable();

        Widget asWidget();

        HasText getDesirableStartTimeInfoLabel();
    }
}
